/*
 * @(#)OptionsTag.java
 *
 * Copyright (c) 2004 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */

package com.dcivision.calendar.taglib;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.util.ResponseUtils;

import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.OptionsListConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.Utility;

/**
  OptionsTag.java

  <p>This class is to extend the OptionsTag provided by Apache Struts.<p>
  <p>This Tag just user for schedule.<p>  
  <p>Modification in "struts-html.tld"<br>
  <pre>
     [FROM]
     &lt;tagclass&gt;org.apache.struts.taglib.html.OptionsTag&lt;/tagclass&gt;
     [TO]
     &lt;tagclass&gt;com.dcivision.framework.taglib.html.OptionsTag&lt;/tagclass&gt;

     [ADDED]
     &lt;attribute&gt;
     &lt;name&gt;dbListName&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;listName&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;listArg1&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;listArg2&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;stringArray&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;hasSelect&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;displayLabel&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;nameValue&lt;/name&gt;
     &lt;required&gt;true&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;width&lt;/name&gt;
     &lt;required&gt;true&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;height&lt;/name&gt;
     &lt;required&gt;true&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;
     &lt;attribute&gt;
     &lt;name&gt;rawMessage&lt;/name&gt;
     &lt;required&gt;false&lt;/required&gt;
     &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
     &lt;/attribute&gt;

 *
  </pre>
  </p>

  <p>USAGE:</p>
  <p>The following example shows that the options which retriving the table
     SETUP_OPTION_COUNTRY.</p>
  <p><code>&lt;html:checkboxOptions <strong>name='fieldName' nameValue='StringAry' dbListName='countryList' hasSelect='false'</strong> /&gt;</code></p>
  <p>The following example shows that the options which retriving the predefined
     options of criteria list used in list search function.</p>
  <p><code>&lt;html:options <strong>listName='criteriaList'</strong>/&gt;</code></p>
  <p>All the list name are defined in <code>com.dcivision.framework.OptionsListConstant</code>

    @author          Beyond Qu
    @company         DCIVision Limited
    @creation date   03/08/2004
    @version         $Revision: 1.4.2.3 $
*/

public class CheckboxOptionsTag extends org.apache.struts.taglib.html.OptionsTag {

  public static final String REVISION = "$Revision: 1.4.2.3 $";

  protected String[][] saStringArray = null;
  protected String sDbListName = null;
  protected String sListName = null;
  protected String sListArg1 = null;
  protected String sListArg2 = null;
  protected boolean bHasSelect = false;
  protected String sDisplayLabel = null;
  protected boolean textOnly = false;
  protected String sName = null;
  protected String[] sNameValue = null;
  protected String sWidth = null;
  protected String sHeight = null;
  protected boolean bRawMessage = false;

  //define a variable for the checkbox is disabled or not.
  protected boolean sDisabled=false;

  //define a String[] to disable the sNameValue
  protected String[] sDisabledNameValue = null;
  protected Hashtable hDisableNameValue = new Hashtable();
  protected boolean optDisable = false;
  
  private static final Log log = LogFactory.getLog(CheckboxOptionsTag.class);
  public CheckboxOptionsTag() {
    super();
  }

  public String[][] getStringArray() {
    return saStringArray;
  }

  public void setStringArray(String[][] strAry) {
    this.saStringArray = strAry;
  }

  public String getDbListName() {
    return sDbListName;
  }

  public void setDbListName(String sDbListName) {
    this.sDbListName = sDbListName;
  }

  public String getListName() {
    return sListName;
  }

  public void setListName(String sListName) {
    this.sListName = sListName;
  }

  public String getListArg1() {
    return sListArg1;
  }

  public void setListArg1(String sListArg1) {
    this.sListArg1 = sListArg1;
  }

  public String getListArg2() {
    return sListArg2;
  }

  public void setListArg2(String sListArg2) {
    this.sListArg2 = sListArg2;
  }

  public boolean getHasSelect() {
    return bHasSelect;
  }

  public void setHasSelect(boolean bHasSelect) {
    this.bHasSelect = bHasSelect;
  }

  public String getDisplayLabel() {
    return sDisplayLabel;
  }

  public void setDisplayLabel(String sDisplayLabel) {
    this.sDisplayLabel = sDisplayLabel;
  }

  public String getName() {
    return sName;
  }

  public void setName(String sName) {
    this.sName = sName;
  }

  public String[] getNameValue() {
    return this.sNameValue;
  }

  public void setNameValue(String[] sNameValue) {
    this.sNameValue = sNameValue;
  }

  public String[] getDisabledNameValue() {
    return this.sDisabledNameValue;
  }

  public void setDisabledNameValue(String[] sDisabledNameValue) {
    this.sDisabledNameValue = sDisabledNameValue;
  }

  public String getWidth() {
    return sWidth;
  }

  public void setWidth(String sWidth) {
    this.sWidth = sWidth;
  }

  public String getHeight() {
    return sHeight;
  }

  public void setHeight(String sHeight) {
    this.sHeight = sHeight;
  }

  public boolean getRawMessage() {
    return bRawMessage;
  }

  public void setRawMessage(boolean bRawMessage) {
    this.bRawMessage = bRawMessage;
  }
  public boolean getDisabled() {
    return sDisabled;
  }

  public void setDisabled(boolean sDisabled) {
    this.sDisabled = sDisabled;
  }

  /**
   * doStartTag
   *
   * Set the attributes 'name' and 'labelName',
   * according to dbListName or listName
   * If both are set, only dbListName is considered
   *
   * @return   SKIP_BODY
   */
  public int doStartTag() throws JspException {

    /* Initiate the disabled name value string[] into Hashtable */
    if (!Utility.isEmpty(sDisabledNameValue)){
      for (int i=0; i<sDisabledNameValue.length; i++){
        hDisableNameValue.put(sDisabledNameValue[i], sDisabledNameValue[i]);
      }
    }


    SessionContainer sessionContainer = (SessionContainer)this.pageContext.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    if ( sDbListName!=null ) {
      List lsName = new ArrayList();
      List lsLabelName = new ArrayList();
      PreparedStatement stat = null;
      ResultSet rs = null;
      Connection conn = (Connection)pageContext.getRequest().getAttribute(GlobalConstant.DB_KEY);

      // get the ID and 2nd column from the table according to dbListName
      try {
        stat = conn.prepareStatement( getSqlStatement(sDbListName) );
        rs = stat.executeQuery();

        while ( rs.next() ) {
          if(!lsName.contains(rs.getString(1))){  
          	lsName.add( rs.getString(1) );
          	lsLabelName.add( rs.getString(2) );
          }
        }
      } catch (Exception e) {
        log.error(e, e);
        throw new JspException(e);
      } finally {
        try { stat.close(); } catch (Exception ignore) {} finally { stat = null; }
        try { rs.close(); } catch (Exception ignore) {} finally { rs = null; }
      }

      // set attribute 'name' and 'labelName'
      pageContext.setAttribute("name", lsName);
      pageContext.setAttribute("labelName", lsLabelName);
      super.setName("name");
      super.setLabelName("labelName");

    } else if ( sListName!=null ) {
      if (OptionsListConstant.LIST_CRITERIA.equals(sListName)) {
        this.setHasSelect(false);
      }

      String[] asName = null;
      String[] asLabelName = null;
      Object[] aoTempAry = null;

      // find the name and labelName according to sListName
      try {
        aoTempAry = getListData(sListName);
      } catch (Exception e) {
        throw new JspException(e);
      }

      asName = (String[])aoTempAry[0];
      asLabelName = (String[])aoTempAry[1];

      // set attribute 'name' and 'labelName'
      pageContext.setAttribute("name", asName);
      pageContext.setAttribute("labelName", asLabelName);
      super.setName("name");
      super.setLabelName("labelName");
    } else if ( saStringArray!= null ) {
      ArrayList alLabels = new ArrayList();
      ArrayList alValues = new ArrayList();
      String[] saLabels = null;
      String[] saValues = null;

      for (int i=0; i< saStringArray.length; i++) {
        alLabels.add(saStringArray[i][0]);
        alValues.add(saStringArray[i][1]);
      }

      saLabels = (String[])alLabels.toArray(new String[0]);
      saValues = (String[])alValues.toArray(new String[0]);

      pageContext.setAttribute("name", saValues);
      pageContext.setAttribute("labelName", this.getLabels(saLabels));
      super.setName("name");
      super.setLabelName("labelName");
    }
    return(SKIP_BODY);

  }

  /**
   * doEndTag
   *
   * @return
   * @throws JspException
   */
  public int doEndTag() throws JspException {
    try {
      pageContext.getOut().print(this.src());
      //return(SKIP_BODY);
      return EVAL_PAGE;
    }
    catch (Exception e) {
      throw new JspException(e);
    }
  }

  protected String src() throws javax.servlet.jsp.JspException {
    HttpServletRequest request = (HttpServletRequest)this.pageContext.getRequest();
    String actionMode = (String) request.getAttribute(GlobalConstant.ACTION_MODE);

    String lyrBgColor = "#FFFFFF";
    if (GlobalConstant.NAV_MODE_VIEW.equals(actionMode)) {
      lyrBgColor = "#EEEEEE";
    }
    StringBuffer sbResult = new StringBuffer();
    if (sWidth==null){
      sWidth="300px";
    }
    if (sHeight==null) {
      sHeight="80px";
    }
    sbResult.append("<div id=\"optionDiv\" class=\"form-style-2-optionsDiv\" style=\"width:"+sWidth+";height:"+sHeight+";background-color:"+lyrBgColor+";layer-background-color:"+lyrBgColor+";\">");
    Iterator valuesIterator = getIterator(name, property);
    Iterator labelsIterator = null;
    if ( (labelName == null) && (labelProperty == null)) {
      labelsIterator = getIterator(name, property); // Same coll.
    }else {
      labelsIterator = getIterator(labelName, labelProperty);
    }
    // Render the options tags for each element of the values coll.
    while (valuesIterator.hasNext()) {
      Object valueObject = valuesIterator.next();
      if (valueObject == null) {
        valueObject = "";
      }
      String value = valueObject.toString();
      String label = value;
      if (labelsIterator.hasNext()) {
        Object labelObject = labelsIterator.next();
        if (labelObject == null) {
          labelObject = "";
        }
        label = labelObject.toString();
      }

      if (GlobalConstant.NAV_MODE_VIEW.equals(actionMode)) {
       StringBuffer labelValue = new StringBuffer(ResponseUtils.filter(label));
       sbResult.append("<nobr><input type='checkbox' name='");
       sbResult.append(sName);
       sbResult.append("' value='" + ResponseUtils.filter(value.toString())+"' ");
       if (this.sNameValue!=null) {
         for (int i=0; i<sNameValue.length; i++){
           if (value.equals(sNameValue[i])) {
             sbResult.append("checked=\"checked\" ");
             break;
           }
         }
       }
       sbResult.append("onclick=\"return(false);\" onselect=\"return(false);\" onchange=\"return(false);\"");
       if(sDisabled){
         sbResult.append(" disabled>" + labelValue + " </nobr><br>");
       }else{
       sbResult.append(">"+labelValue+" </nobr><br>");
       }

      }//Edit option
      else {
        StringBuffer labelValue = new StringBuffer(ResponseUtils.filter(label));
        sbResult.append("<nobr><input type='checkbox' name='");
        sbResult.append(sName);
        sbResult.append("' value='" + ResponseUtils.filter(value.toString())+"' ");
        if (this.sNameValue!=null) {
          for (int i=0; i<sNameValue.length; i++){
            if (value.equals(sNameValue[i])) {
              sbResult.append("checked=\"checked\" ");
              break;
            }

          }
        }else{ //No parameter; check for options to select all
          if (bHasSelect) { //pass variable for all selection
            sbResult.append("checked=\"checked\" ");
          }
        }
        if (hDisableNameValue.containsKey(value)) {
          optDisable = true;
        }else{
          optDisable = false;
        }

        if(sDisabled || optDisable){
          sbResult.append(" disabled>" + labelValue + " </nobr><br>");
        }else{
        sbResult.append(">"+labelValue+" </nobr><br>");
        }
      }

    }
    sbResult.append("</div>");
    return (sbResult.toString());
  }

  /**
   * getLabels
   *
   * @param asMsgKeys  String array of message keys.
   * @return           String array after translation of message keys.
   */
  private String[] getLabels(String[] asMsgKeys) {
    String[] asResult = new String[asMsgKeys.length];
    Locale currLoc = (Locale)pageContext.getSession().getAttribute(org.apache.struts.Globals.LOCALE_KEY);
    for (int i=0; i<asMsgKeys.length; i++) {
      if (!bRawMessage) {
        asResult[i] = MessageResourcesFactory.getMessage(currLoc, asMsgKeys[i]);
      } else {
        asResult[i] = asMsgKeys[i];
      }
    }
    return(asResult);
  }

  /**
   * release
   *
   * Release any acquired resources.
   */
  public void release() {
    super.release();
    saStringArray = null;
    sDbListName = null;
    sListName = null;
    sListArg1 = null;
    sListArg2 = null;
    bHasSelect = false;
    bRawMessage = false;
  }

  /**
   * getSqlStatement
   *
   * Prepare SQL string according to sListName
   * Available list to table mapping:
   * countryList    -- SETUP_OPTION_COUNTRY
   * salutationList -- SETUP_OPTION_SALUTATION
   *
   * @param  sListName     The list name of the table
   * @return SQL string
   */
  private String getSqlStatement(String sDbListName) throws Exception {
    StringBuffer sqlStat = new StringBuffer();

    // select query to table according to sListName
    if ( OptionsListConstant.DBLIST_USER_RECORD.equals(sDbListName) ) {
      sqlStat.append("SELECT A.ID ,A.FULL_NAME FROM USER_RECORD A "); 
      sqlStat.append("INNER JOIN MTM_USER_RECORD_USER_ROLE B ON A.ID "); 
      sqlStat.append("= B.USER_RECORD_ID INNER JOIN USER_ROLE_PERMISSION "); 
      sqlStat.append("C ON B.USER_ROLE_ID = C.USER_ROLE_ID AND C.OBJECT_ID "); 
      sqlStat.append("= 5001 UNION ALL SELECT A.ID ,A.FULL_NAME FROM USER_RECORD "); 
      sqlStat.append("A INNER JOIN MTM_USER_RECORD_USER_GROUP B ON A.ID = "); 
      sqlStat.append("B.USER_RECORD_ID INNER JOIN MTM_USER_GROUP_USER_ROLE "); 
      sqlStat.append("C ON B.USER_GROUP_ID = C.USER_GROUP_ID INNER JOIN "); 
      sqlStat.append("USER_ROLE_PERMISSION D ON C.USER_ROLE_ID = D.USER_ROLE_ID "); 
      sqlStat.append("AND D.OBJECT_ID = 5001  order by A.FULL_NAME ");
      
    } else if ( OptionsListConstant.DBLIST_USER_PUBLIC_GROUP.equals(sDbListName) ) {
      sqlStat.append("SELECT A.ID,A.GROUP_NAME FROM USER_GROUP A  ");
      sqlStat.append("INNER JOIN MTM_USER_GROUP_USER_ROLE B ON A.ID ");
      sqlStat.append("= B.USER_GROUP_ID INNER JOIN  USER_ROLE_PERMISSION ");
      sqlStat.append("C ON B.USER_ROLE_ID = C.USER_ROLE_ID AND C.OBJECT_ID ");
      sqlStat.append("= 5001 ORDER BY A.GROUP_NAME");
      
    } else if ( OptionsListConstant.DBLIST_USER_ROLE.equals(sDbListName) ) {      
      sqlStat.append("SELECT A.ID,A.ROLE_NAME FROM USER_ROLE A "); 
      sqlStat.append("INNER JOIN USER_ROLE_PERMISSION B ON A.ID = "); 
      sqlStat.append("B.USER_ROLE_ID AND  B.OBJECT_ID = 5001 ORDER BY A.ROLE_NAME" );
      
    } else {
      throw new Exception("No List Found");
    }
    return sqlStat.toString();
  }

  /**
   * getListData
   *
   * Get name and labelName of the list
   * Available list: criteriaList
   *
   * @param  sListName
   * @return Object array storing array of name and array of labelName
   */
  private Object[] getListData(String sListName) throws Exception {
    String[] asName;
    String[] asLabelName;

    if ( OptionsListConstant.LIST_CRITERIA.equals(sListName) ) {
      asName = new String[] { "LIKE", "=", "<>", ">=", ">", "<", "<=" };
      asLabelName = new String[] { "common.options.criteria.contains",
                                   "common.options.criteria.equals",
                                   "common.options.criteria.not_equals",
                                   "common.options.criteria.greater_than_or_equals",
                                   "common.options.criteria.greater_than",
                                   "common.options.criteria.less_than",
                                   "common.options.criteria.less_than_or_equals"
                                 };
    } else if ( OptionsListConstant.LIST_STATUS_TYPE.equals(sListName) ) {
      asName = new String[] {GlobalConstant.STATUS_ACTIVE, GlobalConstant.STATUS_INACTIVE};
      asLabelName = new String[] { "common.options.status_A",
                                   "common.options.status_I"
                                 };
    } else if ( OptionsListConstant.LIST_RELEASE_STATUS.equals(sListName) ) {
      asName = new String[] {GlobalConstant.RECORD_PENDING, GlobalConstant.RECORD_RELEASED};
      asLabelName = new String[] { "common.options.status_P",
                                   "common.options.status_R"
                                  };
    } else {
      throw new Exception("No List Found");
    }

    return new Object[] { asName, this.getLabels(asLabelName) };
  }

}
